import type {
  InterviewQuestionWithCode,
  InterviewQuestions,
} from '@/models/InterviewQuestions/InterviewQuestions'
import type { RandomTestingStore } from '.'
import { computed, ref } from 'vue'
import {
  RandomTestingConstants,
  RandomTestingPageType,
  TestTypeKey,
} from '../constants/RandomTesting'
import { page, view } from '@/apis/InterviewQuestions'
import { notification } from 'ant-design-vue'
import { listGetShuffle } from 'rubbish-tool'

const entityName = '实体'

export class RandomTestStore {
  constructor(rootStore: RandomTestingStore) {
    this.rootStore = rootStore
  }

  rootStore

  /**
   * 初始化
   */
  init = () => {
    this.initDoneMap()
    this.initQuestionIdList()
    this.initQuestionTotal()
    this.initQuestionCurrentIndex()
    this.initQuestionPageSize()
    this.initQuestionPageIndex()
  }

  /**
   * 重置数据
   */
  reset = () => {
    this.resetQuestionIdList()
    this.resetQuestionTotal()
    this.resetQuestionCurrentIndex()
    this.resetQuestionPageSize()
    this.resetQuestionPageIndex()
  }

  typeAndCode = computed(() => {
    const { rootStore } = this
    const { classificationStore } = rootStore
    const { type, code } = classificationStore
    if (!type.value || !code.value) return 'all_test'
    return `${type.value}&${code.value}`
  })

  /**
   * 已完成题目
   */
  doneList = ref<InterviewQuestionWithCode[]>([])

  /**
   * 已完成题目id数组
   */
  doneIdList = computed(() => {
    const { doneList } = this
    return doneList.value.map((item) => item.id)
  })

  currentClassDoneIdList = computed(() => {
    const { doneList, rootStore } = this
    const { classificationStore } = rootStore
    const { classificationCode, secondaryClassificationCode } = classificationStore
    return doneList.value
      .filter((item) => {
        if (classificationCode.value) {
          if (item.classification !== classificationCode.value) return false
        }
        if (secondaryClassificationCode.value) {
          if (item.secondaryClassification !== secondaryClassificationCode.value) return false
        }
        return true
      })
      .map((item) => item.id)
  })

  initDoneMap = () => {
    const doneMapStr = localStorage.getItem(RandomTestingConstants.localStorageId.DoneQuestionMap)
    if (!doneMapStr) return
    let doneList = []
    try {
      doneList = JSON.parse(doneMapStr)
    } catch (error) {}
    if (!Array.isArray(doneList)) return
    this.doneList.value = doneList
  }

  setDoneList = (doneMap: InterviewQuestionWithCode[]) => {
    this.doneList.value = doneMap
    const doneMapStr = JSON.stringify(doneMap)
    localStorage.setItem(RandomTestingConstants.localStorageId.DoneQuestionMap, doneMapStr)
  }
  resetDoneList = () => {
    this.doneList.value = []
    localStorage.removeItem(RandomTestingConstants.localStorageId.DoneQuestionMap)
  }
  resetCurrentTestDoneList = () => {
    const { rootStore } = this
    const { classificationStore } = rootStore
    const { secondaryClassificationCode, classificationCode } = classificationStore
    if (!classificationCode.value && !secondaryClassificationCode.value) {
      this.resetDoneList()
      return
    }
    const doneList = this.doneList.value.filter((item) => {
      if (classificationCode.value) {
        return item.classification === classificationCode.value
      }
      if (secondaryClassificationCode.value) {
        return item.secondaryClassification === secondaryClassificationCode.value
      }
      return true
    })
    this.setDoneList(doneList)
  }

  lastDelToggleDoneListIndex = -1
  lastDelDoneInfo: InterviewQuestionWithCode | undefined

  toggleDoneList = (doneQuestion: InterviewQuestionWithCode) => {
    const doneList = this.doneList.value
    const targetIndex = doneList.findIndex((item) => {
      return item.id === doneQuestion.id
    })
    if (targetIndex === -1) {
      if (this.lastDelToggleDoneListIndex !== -1 && this.lastDelDoneInfo?.id === doneQuestion.id) {
        doneList.splice(this.lastDelToggleDoneListIndex, 0, {
          id: doneQuestion.id,
          classification: doneQuestion.classification,
          secondaryClassification: doneQuestion.secondaryClassification,
        })
      } else {
        doneList.push({
          id: doneQuestion.id,
          classification: doneQuestion.classification,
          secondaryClassification: doneQuestion.secondaryClassification,
        })
        this.lastDelToggleDoneListIndex = -1
      }
    } else {
      this.lastDelToggleDoneListIndex = targetIndex
      this.lastDelDoneInfo = doneQuestion
      doneList.splice(targetIndex, 1)
    }
    this.setDoneList(doneList)
  }

  questionIdList = ref<number[]>([])
  questionIdListKey = computed(() => {
    const { typeAndCode } = this
    return `${RandomTestingConstants.localStorageId.QuestionIdList}:${typeAndCode.value}`
  })

  initQuestionIdList = () => {
    const { questionIdListKey } = this
    const localStr = localStorage.getItem(questionIdListKey.value)
    if (!localStr) {
      this.questionIdList.value = []
      return
    }
    const localValue = JSON.parse(localStr)
    if (!Array.isArray(localValue)) {
      this.questionIdList.value = []
      return
    }
    this.questionIdList.value = localValue
  }

  setQuestionIdList = (idList: number[]) => {
    const { questionIdListKey } = this
    this.questionIdList.value = idList
    localStorage.setItem(questionIdListKey.value, JSON.stringify(idList))
  }

  resetQuestionIdList = () => {
    const { questionIdListKey } = this
    this.questionIdList.value = []
    localStorage.removeItem(questionIdListKey.value)
  }

  questionTotal = ref<number>(0)
  questionTotalKey = computed(() => {
    const { typeAndCode } = this
    return `${RandomTestingConstants.localStorageId.QuestionTotal}:${typeAndCode.value}`
  })

  showQuestionTotal = computed(() => {
    const { questionTotal, currentClassDoneIdList, rootStore } = this
    const { classificationStore } = rootStore
    const { testType } = classificationStore
    switch (testType.value) {
      case TestTypeKey.All: {
        return questionTotal.value
      }
      case TestTypeKey.Done: {
        return currentClassDoneIdList.value.length
      }
      case TestTypeKey.NotDone:
      default: {
        return questionTotal.value - currentClassDoneIdList.value.length
      }
    }
  })

  initQuestionTotal = () => {
    const { questionTotalKey } = this
    const localStr = localStorage.getItem(questionTotalKey.value)
    if (!localStr) {
      this.questionTotal.value = 0
      return
    }
    const localValue = JSON.parse(localStr)
    if (typeof localValue !== 'number') {
      this.questionTotal.value = 0
      return
    }
    this.questionTotal.value = localValue
  }

  setQuestionTotal = (total: number) => {
    const { questionTotalKey } = this
    this.questionTotal.value = total
    localStorage.setItem(questionTotalKey.value, JSON.stringify(total))
  }

  resetQuestionTotal = () => {
    const { questionTotalKey } = this
    this.questionTotal.value = 0
    localStorage.removeItem(questionTotalKey.value)
  }

  questionCurrentIndex = ref<number>(0)
  questionCurrentIndexKey = computed(() => {
    const { typeAndCode } = this
    return `${RandomTestingConstants.localStorageId.QuestionCurrentIndex}:${typeAndCode.value}`
  })

  initQuestionCurrentIndex = () => {
    const { questionCurrentIndexKey } = this
    const localStr = localStorage.getItem(questionCurrentIndexKey.value)
    if (!localStr) {
      this.questionCurrentIndex.value = 0
      return
    }
    const localValue = JSON.parse(localStr)
    if (typeof localValue !== 'number') {
      this.questionCurrentIndex.value = 0
      return
    }
    this.questionCurrentIndex.value = localValue
  }

  setQuestionCurrentIndex = (currentIndex: number) => {
    const setValue = currentIndex >= 0 ? currentIndex : 0
    const { questionCurrentIndexKey } = this
    this.questionCurrentIndex.value = setValue
    localStorage.setItem(questionCurrentIndexKey.value, JSON.stringify(setValue))
  }

  resetQuestionCurrentIndex = () => {
    const { questionCurrentIndexKey } = this
    this.questionCurrentIndex.value = 0
    localStorage.removeItem(questionCurrentIndexKey.value)
  }

  questionPageSize = ref<number>(20)
  questionPageSizeKey = computed(() => {
    const { typeAndCode } = this
    return `${RandomTestingConstants.localStorageId.QuestionPageSize}:${typeAndCode.value}`
  })

  initQuestionPageSize = () => {
    const { questionPageSizeKey } = this
    const localStr = localStorage.getItem(questionPageSizeKey.value)
    if (!localStr) {
      this.questionPageSize.value = 20
      return
    }
    const localValue = JSON.parse(localStr)
    if (typeof localValue !== 'number') {
      this.questionPageSize.value = 20
      return
    }
    this.questionPageSize.value = localValue
  }

  setQuestionPageSize = (pageSize: number) => {
    const { questionPageSizeKey } = this
    this.questionPageSize.value = pageSize
    localStorage.setItem(questionPageSizeKey.value, JSON.stringify(pageSize))
  }
  resetQuestionPageSize = () => {
    const { questionPageSizeKey } = this
    this.questionPageSize.value = 20
    localStorage.removeItem(questionPageSizeKey.value)
  }

  questionPageIndex = ref<number>(0)
  questionPageIndexKey = computed(() => {
    const { typeAndCode } = this
    return `${RandomTestingConstants.localStorageId.QuestionPageIndex}:${typeAndCode.value}`
  })

  initQuestionPageIndex = () => {
    const { questionPageIndexKey } = this
    const localStr = localStorage.getItem(questionPageIndexKey.value)
    if (!localStr) {
      this.questionPageIndex.value = 0
      return
    }
    const localValue = JSON.parse(localStr)
    if (typeof localValue !== 'number') {
      this.questionPageIndex.value = 0
      return
    }
    this.questionPageIndex.value = localValue
  }

  setQuestionPageIndex(pageIndex: number) {
    const { questionPageIndexKey } = this
    this.questionPageIndex.value = pageIndex
    localStorage.setItem(questionPageIndexKey.value, JSON.stringify(pageIndex))
  }
  resetQuestionPageIndex() {
    const { questionPageIndexKey } = this
    this.questionPageIndex.value = 0
    localStorage.removeItem(questionPageIndexKey.value)
  }

  testQuestionIdList = computed(() => {
    const { rootStore, questionIdList, doneIdList, currentClassDoneIdList } = this
    const { classificationStore } = rootStore
    const { testType } = classificationStore
    switch (testType.value) {
      case TestTypeKey.NotDone: {
        return questionIdList.value.filter((id) => !doneIdList.value.includes(id))
      }
      case TestTypeKey.Done: {
        return currentClassDoneIdList.value
      }
      case TestTypeKey.All:
      default: {
        return questionIdList.value
      }
    }
  })

  loadingQuestion = ref(false)

  question = ref<InterviewQuestions>()

  initQuestion = async () => {
    const { rootStore } = this
    const { classificationStore } = rootStore
    const { testType } = classificationStore
    this.loadingQuestion.value = true
    try {
      switch (testType.value) {
        case TestTypeKey.Done: {
          await this.initDoneTestTypeQuestion()
          break
        }
        case TestTypeKey.NotDone: {
          await this.initAllAndNotDoneTestTypeQuestion()
          break
        }
        case TestTypeKey.All:
        default: {
          await this.initAllAndNotDoneTestTypeQuestion()
          break
        }
      }
    } catch (error) {
      console.error(error)
      notification.error({ message: `初始化${entityName}失败!` })
    }
    this.loadingQuestion.value = false
  }

  initAllAndNotDoneTestTypeQuestion = async () => {
    const {
      testQuestionIdList,
      questionCurrentIndex,
      rootStore,
      questionPageIndex,
      questionPageSize,
    } = this
    const { plainStore, classificationStore } = rootStore
    const { classification, secondaryClassification } = classificationStore
    if (questionCurrentIndex.value < 0) {
      // 索引错误
      plainStore.setPageType(RandomTestingPageType.ErrorPage)
      return
    }
    while (questionCurrentIndex.value >= testQuestionIdList.value.length) {
      // 索引不足
      // 分页获取
      const res = await page({
        page: questionPageIndex.value + 1,
        size: questionPageSize.value,
        classification: classification.value?.code,
        secondaryClassification: secondaryClassification.value?.code,
        excludelds: [],
      })
      if (res.data) {
        const { list, total, lastPage } = res.data
        if (!Array.isArray(list) || !list.length || questionPageIndex.value + 1 > lastPage) {
          plainStore.setPageType(RandomTestingPageType.DonePage)
          this.setQuestionCurrentIndex(questionCurrentIndex.value - 1)
          return
        }
        this.setQuestionIdList([
          ...this.questionIdList.value,
          ...listGetShuffle(list.map(({ id }) => id)),
        ])
        this.setQuestionPageIndex(questionPageIndex.value + 1)
        this.setQuestionTotal(total)
      } else {
        throw new Error('分页接口返回数据错误!')
      }
    }
    if (questionCurrentIndex.value >= testQuestionIdList.value.length) {
      plainStore.setPageType(RandomTestingPageType.DonePage)
      this.setQuestionCurrentIndex(questionCurrentIndex.value - 1)
      return
    }
    const questionId = testQuestionIdList.value[questionCurrentIndex.value]
    const questionRes = await view(questionId)
    if (questionRes.data) {
      this.question.value = questionRes.data
    } else {
      throw new Error(`获取${questionId}题目数据错误!`)
    }
  }

  initDoneTestTypeQuestion = async () => {
    const { testQuestionIdList, questionCurrentIndex, rootStore } = this
    const { plainStore } = rootStore
    if (questionCurrentIndex.value < 0) {
      // 索引错误
      plainStore.setPageType(RandomTestingPageType.ErrorPage)
      return
    }
    if (questionCurrentIndex.value >= testQuestionIdList.value.length) {
      // 索引不足
      plainStore.setPageType(RandomTestingPageType.DonePage)
      this.setQuestionCurrentIndex(questionCurrentIndex.value - 1)
      return
    }
    const questionId = testQuestionIdList.value[questionCurrentIndex.value]
    const questionRes = await view(questionId)
    if (questionRes.data) {
      this.question.value = questionRes.data
    } else {
      throw new Error(`获取${questionId}题目数据错误!`)
    }
    this.setQuestionTotal(testQuestionIdList.value.length)
  }
}
